package com.huihe.framework.filter;

import com.huihe.common.utils.SecurityUtils;
import com.huihe.storage.dto.LoginUser;
import com.huihe.framework.service.TokenService;
import io.micrometer.common.lang.NonNullApi;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Component
@NonNullApi
@AllArgsConstructor
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    /**
     * Token的Service
     */
    private TokenService tokenService;

    /**
     * 解析Token,并将对应的用户信息存入上下文
     * @param request 请求
     * @param response 响应
     * @param filterChain 表示当前请求的过滤器链
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //通过Token取出Redis中的用户信息
        LoginUser loginUser = tokenService.getLoginUserByToken(request);
        //当前Token找到对应的用户,并且SecurityContext上下文中没有用户信息
        if (loginUser != null && SecurityUtils.getAuthentication() == null) {
            //见擦汗Token有效期是不是过短，从而刷新
            tokenService.verifyToken(loginUser);
            //创建 authenticationToken 用户名和密码的认证信息
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
            //将更详细的信息存入 authenticationToken 中,如客户端IP等
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            //将 authenticationToken 存入 SecurityContext 上下文中
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        //传递给下一个过滤器链
        filterChain.doFilter(request, response);
    }
}
